/*
 * stepper.h
 *
 *  Created on: 7-Jul-2009
 *      Author: nrqm
 */

#ifndef STEPPER_H_
#define STEPPER_H_

#include "avr/io.h"
#include "../arduino/WProgram.h"
#include "../midi/midi.h"

/**
 * The stepper motor object.
 */
class Stepper : public MidiPitchBendListener
{
//private:
public:

	/**
	 * The members of this enumeration have values matching the pin outputs for each cycle.
	 */
	/*typedef enum _sts {
		CYCLE1=EN0 | L1,
		CYCLE2=EN0 | L2,
		CYCLE3=EN1 | L3,
		CYCLE4=EN1 | L4,
	} STEPPER_STATE;*/
	typedef enum _sts {
		CYCLE1=0,
		CYCLE2=1,
		CYCLE3=2,
		CYCLE4=3,
	} STEPPER_STATE;

	/// The cycle that the stepper currently has charged.  There are four cycles to a step.
	STEPPER_STATE state;
	/// The maximum number of positions that the stepper can traverse (positions are one step apart).
	uint8_t max_positions;
	/// The drumstick's current position.  0 is the centre (default), max_positions is the rightmost edge.
	uint8_t current_position;
	/// The position where the drumstick is supposed to be.  If this differs from current_position, the stepper turns.
	uint8_t destination_position;
	/// The Timer::Now value when the current stepper cycle started (if the stepper is turning).
	uint16_t current_cycle_start_time;
	/// The pitch bend value that matches the current destination position.
	int16_t current_pitch;
	/**
	 * Constructor.  This is a singleton, so get the instance using Stepper::GetInstance.
	 */
	Stepper();
	/**
	 * Switch the stepper output to a new cycle.  This doesn't enforce the state diagram.
	 */
	void TransitionToState(STEPPER_STATE new_state);
	/**
	 * Output the appropriate pattern for the current cycle to the output pins.
	 */
	void OutputCycleCode();
	/**
	 * Traverse through the stepper state diagram such that the stepper moves a step counterclockwise.
	 */
	void CycleCCW();
	/**
	 * Traverse through the stepper state diagram such that the stepper moves a step clockwise.
	 */
	void CycleCW();
protected:
	/**
	 * Handle a MIDI pitch bend command.  This is called through the MidiListener base class when a new pitch
	 * bend message comes in.
	 */
	void DoPitchBend(int16_t new_pitch);	// TODO: will this actually override the public version?
public:
	/**
	 * Retrieve the instance of this singleton class.
	 */
	static Stepper* GetInstance();
	/**
	 * Check to see if the stepper state needs to be changed.  This should be called from the program's main loop
	 * as often as possible.
	 */
	void CheckStepper();
};

#endif /* STEPPER_H_ */
